[POWERPC][XEN] Track pages correctly
authorJimi Xenidis <jimix@watson.ibm.com>
Wed, 13 Sep 2006 22:41:11 +0000 (18:41 -0400)
committerJimi Xenidis <jimix@watson.ibm.com>
Wed, 13 Sep 2006 22:41:11 +0000 (18:41 -0400)
The following patch tracks and frees pages correctly.  It solves the problem where a foreign mapping would zombie a domain because the refcnts remained.
This involved:
  - implement relinquish_memory() for PowerPC
  - remove free_rma() since all pages get "relinquished" now.
  - foreign pages are get and put correctly

Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
xen/arch/powerpc/domain.c
xen/arch/powerpc/mm.c
xen/arch/powerpc/papr/xlate.c
xen/include/asm-powerpc/mm.h

index ff93bd1cc0aa5679c566be261f1e67342e784355..29bdd54ba8f3439f635481ed2c713e687202637c 100644 (file)
@@ -242,10 +242,44 @@ void sync_vcpu_execstate(struct vcpu *v)
     return;
 }
 
+static void relinquish_memory(struct domain *d, struct list_head *list)
+{
+    struct list_head *ent;
+    struct page_info  *page;
+
+    /* Use a recursive lock, as we may enter 'free_domheap_page'. */
+    spin_lock_recursive(&d->page_alloc_lock);
+
+    ent = list->next;
+    while ( ent != list )
+    {
+        page = list_entry(ent, struct page_info, list);
+
+        /* Grab a reference to the page so it won't disappear from under us. */
+        if ( unlikely(!get_page(page, d)) )
+        {
+            /* Couldn't get a reference -- someone is freeing this page. */
+            ent = ent->next;
+            continue;
+        }
+        if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
+            put_page_and_type(page);
+
+        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+            put_page(page);
+
+        /* Follow the list chain and /then/ potentially free the page. */
+        ent = ent->next;
+        put_page(page);
+    }
+    spin_unlock_recursive(&d->page_alloc_lock);
+}
+
 void domain_relinquish_resources(struct domain *d)
 {
-    free_rma(d);
+    relinquish_memory(d, &d->page_list);
     free_extents(d);
+    return;
 }
 
 void arch_dump_domain_info(struct domain *d)
index cab759891776c559da433db263cf9371e34568a5..46d6db2236efb3300233bfb0ae659fb330450cbd 100644 (file)
@@ -329,13 +329,6 @@ int allocate_rma(struct domain *d, unsigned int order)
     return 0;
 }
 
-void free_rma(struct domain *d)
-{
-    if (d->arch.rma_page) {
-        free_domheap_pages(d->arch.rma_page, d->arch.rma_order);
-    }
-}
-
 ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
 {
     ulong rma_base_mfn = page_to_mfn(d->arch.rma_page);
index 805a0e67854b70918604c832d6d1ca6d232a09ef..7a4da2c1271cb164ac4c0e0121345432860d9015 100644 (file)
@@ -263,6 +263,7 @@ static void h_enter(struct cpu_user_regs *regs)
 
                 BUG_ON(f == d);
                 get_domain(f);
+                get_page(pg, f);
             }
                 break;
             case PFN_TYPE_RMA:
@@ -510,8 +511,10 @@ static void h_remove(struct cpu_user_regs *regs)
             struct page_info *pg = mfn_to_page(mfn);
             struct domain *f = page_get_owner(pg);
 
-            if (f != d)
+            if (f != d) {
                 put_domain(f);
+                put_page(pg);
+            }
         }
     }
 
index b54f9046186fa9ae1d40dc74bc60aa5e6eff42de..0f272286e025ee191a7661a51dc66aa60e8be2aa 100644 (file)
@@ -154,7 +154,6 @@ static inline void put_page(struct page_info *page)
     while ( unlikely((y = cmpxchg(&page->count_info, x, nx)) != x) );
 
     if ( unlikely((nx & PGC_count_mask) == 0) ) {
-        panic("about to free page: 0x%lx\n", page_to_mfn(page));
         free_domheap_page(page);
     }
 }
@@ -259,7 +258,6 @@ static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gmfn)
 #define mfn_to_gmfn(_d, mfn) (mfn)
 
 extern int allocate_rma(struct domain *d, unsigned int order_pages);
-extern void free_rma(struct domain *d);
 extern uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages);
 extern void free_extents(struct domain *d);